package m.fun.service;

import m.appserver.AuthInfoUtil;
import m.base.model.StoreInfo;
import m.base.model.UserInfo;
import m.base.util.PowerUtil;
import m.common.model.util.*;
import m.common.service.Service;
import m.fun.model.BuildOrderModel;
import m.fun.model.ProduceInGoods;
import m.fun.model.ProduceInfo;
import m.fun.model.ProduceOutGoods;
import m.store.model.*;
import m.store.service.OrderRepositoryCheckService;
import m.store.service.SaleInfoService;
import m.store.service.StockInfoService;
import m.store.service.StoreNumberService;
import m.store.task.StoreGoodsSupport;
import m.system.db.TransactionManager;
import m.system.exception.MException;
import m.system.util.*;

import java.util.*;

public class ProduceInfoService extends Service {
    public String save(ProduceInfo model, List<ProduceOutGoods> outGoodsList, List<ProduceInGoods> inGoodsList) throws Exception {
        if(null==outGoodsList||outGoodsList.isEmpty()) throw new MException(this.getClass(),"请添加消耗商品明细");
        if(null==inGoodsList||inGoodsList.isEmpty()) throw new MException(this.getClass(),"请添加生产商品明细");
        ModelQueryCheck.init(model)
            .checkNotNull("produceDate","生产日期不能为空")
            .checkNotNull("guest.oid","请选择客户")
            .checkNotNull("status","状态错误")
            .checkStrEq("status", OrderModel.Status_Register,"登记状态才能修改")
            .doCheck(false,true);
        PowerUtil.verifyAccountDate(model.getProduceDate(),"生产日期");
        String msg="";
        if(ObjectUtil.isEmptyOid(model)){
            model.setOid(GenerateID.generatePrimaryKey());
            ModelUpdateUtil.insertModel(model);
            msg="保存成功";
        }else{
            ModelUpdateUtil.updateModel(model,"guest.oid","produceDate","remark");
            msg="修改成功";
        }
        Double all1=0.0,all2=0.0;
        ModelUpdateUtil.delete(ProduceOutGoods.class, QueryCondition.eq("produce.oid",model.getOid()));
        Map<String,Integer> numMap=new HashMap<>();
        Set<String> error=new HashSet<>();
        for(ProduceOutGoods record : outGoodsList){
            ModelQueryCheck.init(record)
                .checkNotNull("record.oid","请选择消耗库存商品")
                .checkNotNull("num","请输入消耗数量")
                .checkNotNull("price","请输入消耗单价")
                .checkNumberRange("price",0D,999999999D,"消耗单价不能小于0")
                .checkNotNull("preferential","请输入消耗优惠金额")
                .doCheck(false,true);
            GoodsStockRecord stockRecord=ModelQueryList.getModel(record.getRecord(),"*","goods.*");
            numMap.merge(stockRecord.getOid(), record.getNum(), Integer::sum);//累加相同商品数量
            if(stockRecord.getSurplusNum()-numMap.get(stockRecord.getOid())<0)
                error.add(stockRecord.getGoods().getName());
            record.setOid(GenerateID.generatePrimaryKey());
            record.setGoods(stockRecord.getGoods());
            record.setProduce(model);
            record.setOperDate(new Date());
            record.setAmount(NumberUtil.round(record.getNum()*record.getPrice()-record.getPreferential(),2));
            record.setPreferentialPrice(NumberUtil.round((record.getNum()*record.getPrice()-record.getPreferential())/record.getNum(),2));
            all1+= record.getAmount();
        }
        if(!error.isEmpty()) //存在库存不足
            throw new MException(this.getClass(),"库存不足 - "+ ArrayUtil.connection(error.toArray(),","));
        ModelUpdateUtil.insertModels(outGoodsList.toArray(new ProduceOutGoods[0]));
        ModelUpdateUtil.delete(ProduceInGoods.class, QueryCondition.eq("produce.oid",model.getOid()));
        Set<String> inNumMap=new HashSet<>();
        for(ProduceInGoods record : inGoodsList){
            ModelQueryCheck.init(record)
                .checkNotNull("repository.oid","请选择生产仓库信息")
                .checkNotNull("goods.oid","请选择生产商品信息")
                .checkNotNull("price","请输入生产单价")
                .checkNumberRange("price",0D,999999999D,"生产单价不能小于0")
                .checkNotNull("num","请输入生产数量")
                .checkNumberRange("num",1D,999999999D,"生产数量不能小于1")
                .checkNotNull("preferential","请输入生产优惠金额")
                .doCheck(false,true);
            String goodsOid=record.getGoods().getOid();
            StoreGoods goods=ModelQueryList.getModel(record.getGoods());
            if(inNumMap.contains(goodsOid)) throw new MException(this.getClass(),goods.getName()+" 重复添加了");
            inNumMap.add(record.getGoods().getOid());
            record.setOid(GenerateID.generatePrimaryKey());
            record.setProduce(model);
            record.setOperDate(new Date());
            record.setAmount(NumberUtil.round(record.getNum()*record.getPrice()-record.getPreferential(),2));
            record.setPreferentialPrice(NumberUtil.round((record.getNum()*record.getPrice()-record.getPreferential())/record.getNum(),2));
            all2+= record.getAmount();
        }
        if(NumberUtil.round(all1-all2,2)!=0.0)
            throw new MException(this.getClass(),"消耗商品价值和生产商品价值不等，请调整。");
        ModelUpdateUtil.insertModels(inGoodsList.toArray(new ProduceInGoods[0]));
        updateAmount(model.getOid());
        return msg;
    }
    private void updateAmount(String oid) throws MException {
        ModelUpdate.init(ProduceInfo.class)
                .set("produceAmount",ProduceOutGoods.class,"ifnull(sum(#{amount}),0)",QueryCondition.eq("produce.oid",oid))
                .execute(oid);
    }

    /**
     * 提交
     */
    public void saveAndSubmit(ProduceInfo model, List<ProduceOutGoods> outGoodsList,List<ProduceInGoods> inGoodsList,boolean repositoryCheck) throws Exception {
        save(model,outGoodsList,inGoodsList);
        model.setStatus(OrderModel.Status_Check);
        if(repositoryCheck) getService(OrderRepositoryCheckService.class).insertCheck(model);
        model.setSubmitDate(new Date());
        ModelUpdateUtil.updateModel(model,"status","submitDate");
    }
    public void saveAndSubmit(ProduceInfo model, List<ProduceOutGoods> outGoodsList,List<ProduceInGoods> inGoodsList) throws Exception {
        saveAndSubmit(model,outGoodsList,inGoodsList,true);
    }

    /**
     * 删除
     */
    public void delete(String oid, UserInfo user) throws Exception {
        ProduceInfo model=ModelQueryList.getModel(ProduceInfo.class,oid,"*");
        ModelQueryCheck.init(model)
            .checkStrEq("status",OrderModel.Status_Register,"登记中才能删除")
            .checkStrEq("inputUser.oid",user.getOid(),"权限错误")
            .doCheck(false,true);
        ModelUpdateUtil.deleteModel(model);
        ModelUpdateUtil.delete(ProduceOutGoods.class, QueryCondition.eq("produce.oid",model.getOid()));
        ModelUpdateUtil.delete(ProduceInGoods.class, QueryCondition.eq("produce.oid",model.getOid()));
    }

    /**
     * 审核通过
     */
    public void check(String oid, Date produceDate, String remark, StoreInfo store, UserInfo user) throws Exception {
        getService(OrderRepositoryCheckService.class).verifyCheckOver(oid);
        ProduceInfo model=ModelQueryList.getModel(ProduceInfo.class,oid,"*");
        model.setProduceDate(produceDate);
        model.setRemark(remark);
        ModelQueryCheck.init(model)
            .checkNotNull("produceDate","生产日期不能为空")
            .checkStrEq("status",OrderModel.Status_Check,"审核中才能通过")
            .checkStrEq("store.oid",store.getOid(),"权限错误")
            .doCheck(false,true);
        PowerUtil.verifyAccountDate(model.getProduceDate(),"生产日期");
        saveStockAndSale(oid);
        model.setStatus(OrderModel.Status_Done);
        model.setBuildStatus(BuildOrderModel.Build_Done);
        model.setCheckUser(user);
        model.setCheckDate(new Date());
        ModelUpdateUtil.updateModel(model,"buildStatus","status","checkUser.oid","checkDate","produceDate","remark");
    }
    private void saveStockAndSale(String oid) throws Exception {
        ProduceInfo model=ModelQueryList.getModel(ProduceInfo.class,oid,"*");
        String[] goodsOids=new String[0];
        TransactionManager tm=new TransactionManager();
        try {
            tm.begin();
            //生成生产出库
            if(ObjectUtil.isEmptyOid(model.getSale())) {
                List<ProduceOutGoods> recordList=ModelQueryList.getModelList(ProduceOutGoods.class,
                    new String[]{"*","record.*"}, null,
                    QueryCondition.eq("produce.oid", model.getOid())
                );
                SaleInfo sale = new SaleInfo();
                sale.setOrderNo(StoreNumberService.getNextSaleNumber(model.getStore().getOid()));
                sale.setStore(model.getStore());
                sale.setStatus(OrderModel.Status_Register);
                sale.setType(SaleInfo.Type_Produce);
                sale.setInputDate(model.getInputDate());
                sale.setInputUser(model.getInputUser());
                sale.setSaleDate(model.getProduceDate());
                sale.setGuest(model.getGuest());
                sale.setRemark(model.getRemark());
                List<GoodsOutRecord> saleRecords = new ArrayList<>();
                for(ProduceOutGoods item : recordList){
                    GoodsOutRecord record = new GoodsOutRecord();
                    record.setRecord(item.getRecord());
                    record.setNum(item.getNum());
                    record.setPrice(item.getPrice());
                    record.setPreferential(item.getPreferential());
                    record.setRemark(item.getRemark());
                    saleRecords.add(record);
                }
                goodsOids=recordList.stream().map(item->item.getGoods().getOid()).toArray(String[]::new);
                getService(SaleInfoService.class).saveAndSubmit(sale, saleRecords,false);
                getService(SaleInfoService.class).check(sale.getOid(), sale.getSaleDate(), sale.getRemark(), sale.getStore(), model.getCheckUser());
                model.setSale(sale);
                ModelUpdateUtil.updateModel(model, "sale.oid");
            }
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
            throw new MException(this.getClass(),"生成生产出库失败:"+e.getMessage());
        }
        StoreGoodsSupport.doneHandler(goodsOids);
        tm=new TransactionManager();
        try {
            tm.begin();
            //生成生产入库
            if(ObjectUtil.isEmptyOid(model.getStock())) {
                List<ProduceInGoods> recordList=ModelQueryList.getModelList(ProduceInGoods.class,
                    new String[]{"*"}, null,
                    QueryCondition.eq("produce.oid", model.getOid())
                );
                StockInfo stock = new StockInfo();
                stock.setOrderNo(StoreNumberService.getNextStockNumber(model.getStore().getOid()));
                stock.setStore(model.getStore());
                stock.setStatus(OrderModel.Status_Register);
                stock.setType(StockInfo.Type_Produce);
                stock.setInputDate(model.getInputDate());
                stock.setInputUser(model.getInputUser());
                stock.setStockDate(model.getProduceDate());
                stock.setGuest(model.getGuest());
                stock.setRemark(model.getRemark());
                List<GoodsStockRecord> stockRecords = new ArrayList<>();
                for(ProduceInGoods item : recordList){
                    GoodsStockRecord record = new GoodsStockRecord();
                    record.setRepository(item.getRepository());
                    record.setGoods(item.getGoods());
                    record.setStockNum(item.getNum());
                    record.setPrice(item.getPrice());
                    record.setPreferential(item.getPreferential());
                    record.setRemark(item.getRemark());
                    stockRecords.add(record);
                }
                getService(StockInfoService.class).saveAndSubmit(stock, stockRecords,false);
                getService(StockInfoService.class).check(stock.getOid(), stock.getStockDate(), stock.getRemark(), stock.getStore(), model.getCheckUser());
                model.setStock(stock);
                ModelUpdateUtil.updateModel(model, "stock.oid");
            }
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            throw new MException(this.getClass(),"生成生产入库失败:"+e.getMessage());
        }
    }

    /**
     * 退回
     */
    public void refund(String oid, StoreInfo store,UserInfo user) throws Exception {
        ProduceInfo model=ModelQueryList.getModel(ProduceInfo.class,oid,"*");
        ModelQueryCheck.init(model)
            .checkStrEq("status",OrderModel.Status_Check,"审核中才能退回")
            .checkStrEq("store.oid",store.getOid(),"权限错误")
            .doCheck(false,true);
        model.setStatus(OrderModel.Status_Register);
        model.setCheckUser(user);
        model.setCheckDate(new Date());
        model.setRepositoryStatus(StringUtil.isSpace(model.getRepositoryStatus())?null:OrderRepositoryCheck.Status_No);
        ModelUpdateUtil.updateModel(model,"status","checkUser.oid","checkDate","repositoryStatus");
    }
}
